﻿using AutoMapper;
using FlyingEyeClient.ApplicationServices.SignalRHubs;
using HandyControl.Controls;
using log4net;
using MaterialTypeRecognition.Shell.AuthenticationServices;
using MaterialTypeRecognition.Shell.DeviceServices;
using MaterialTypeRecognition.Shell.Logs;
using MaterialTypeRecognition.Shell.MesServices;
using MaterialTypeRecognition.Shell.SaveInfos;
using MaterialTypeRecognition.Shell.SaveInfoService;
using MaterialTypeRecognition.Shell.UserControls;
using MaterialTypeRecognition.Shell.Utils;
using MaterialTypeRecognition.Shell.Views;
using Microsoft.Extensions.DependencyInjection;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace MaterialTypeRecognition.Shell.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        /// <summary>
        /// 当前级片类别
        /// </summary>
        private string? _currentMessage;

        private readonly IServiceProvider _services;

        private readonly ISaveInfoService _saveInfoService;

        private readonly IMapper _mapper;

        private readonly ILog _appLog;

        private readonly ILog _operationLog;

        private readonly TimesUpTimer _timer;

        private readonly InBoundSubscriber _inboundSubscriber;

        private SignalRClientService? _signalRClientService;

        public SignalRClientService SignalRClientService
        {
            get { return _signalRClientService ?? throw new InvalidOperationException("未连接 Hub 服务"); }
        }

        private readonly SiemensSmart200Service _smart200Service;

        public MainWindowViewModel(IServiceProvider services,
            IMapper mapper,
            ILog4NetLoggerFactory factory,
            TimesUpTimer timer,
            InBoundSubscriber inboundSubscriber,
            SiemensSmart200Service siemensSmart200Service)
        {
            _smart200Service = siemensSmart200Service;
            _smart200Service.DeviceWrite += OnDeviceWrite;
            _inboundSubscriber = inboundSubscriber;
            _inboundSubscriber.Inbound += OnInbound;
            _timer = timer;
            _timer.Tick += OnTick;
            _timer.TimesUp += OnTimesUp;
            _appLog = factory.GetAppLogger();
            _operationLog = factory.GetOperationLogger();
            _mapper = mapper;
            _saveInfoService = services.GetRequiredService<ISaveInfoService>();
            _services = services;
            UserManageCommand = new DelegateCommand(OnUserManage);
            ConfigCommand = new DelegateCommand(OnConfig);
            AuthenticateCommand = new DelegateCommand<object>(OnAuthenticate);
            UnregisterCommand = new DelegateCommand(OnUnregister);
            StartCommand = new DelegateCommand(OnInbound);
            OpenCommand = new DelegateCommand(OnOpenBox);
            PositionList = new List<string>()
            {
                "呈现在左上角",
                "呈现在右上角",
                "隐藏提示窗口",
            };

            ControlEnable = false;
            TimerVisibility = Visibility.Collapsed;
            ConnectCommand = new DelegateCommand(OnConnect);

            // 从存储加载属性值
            InitProperties();

            ConnectAsync();
        }

        private void OnDeviceWrite(object? sender, DeviceWriteEventArgs e)
        {
            if (e.IsSuccess)
            {
                LogInformation(e.Message);
            }
            else
            {
                LogError(e.Message);
            }
        }

        private void InitProperties()
        {
            var saveInfo = _saveInfoService.Read<MainWindowSaveInfo>();
            this.DeviceId = saveInfo.DeviceId;
            this.IPAddress = saveInfo.IPAddress;
            this.Port = saveInfo.Port;
        }

        public ICommand OpenCommand { get; set; }

        private bool _hasOpen = false;

        public void OnOpenBox()
        {
            if (string.IsNullOrEmpty(this.IPAddress)
               || string.IsNullOrEmpty(this.DeviceId)
               || this.Port <= 0 || this.Port > 65535)
            {
                LogError("PLC 配置参数无效！");
            }
            else
            if (string.IsNullOrWhiteSpace(_currentMessage))
            {
                LogError("级片未分类，请手动分类，或者等待下一次上料自动分类！");
            }
            else
            {
                UpdateTopTip(_currentMessage);
            }
        }

        public ICommand ConnectCommand { get; set; }

        private bool HubConnected { get; set; }

        private void OnConnect()
        {
            if (!HubConnected)
            {
                ConnectAsync();
            }
            else
            {
                DisconnectAsync();
            }
        }

        public string DeviceId { get; set; } = string.Empty;

        /// <summary>
        /// 回收箱子 IP 地址
        /// </summary>
        public string IPAddress { get; set; } = string.Empty;

        /// <summary>
        /// 回收箱子端口
        /// </summary>
        public int Port { get; set; }

        private bool _canClickConnectionButton;

        public bool CanClickConnectionButton
        {
            get { return _canClickConnectionButton; }
            set { SetProperty(ref _canClickConnectionButton, value); }
        }

        private string _connectionButtonContent = "连接服务器";

        public string ConnectionButtonContent
        {
            get { return _connectionButtonContent; }
            set { SetProperty(ref _connectionButtonContent, value); }
        }

        private bool _canEditDeviceId;

        public bool CanEditDeviceId
        {
            get { return _canEditDeviceId; }
            set { SetProperty(ref _canEditDeviceId, value); }
        }


        /// <summary>
        /// 在启动的时候，连接服务器
        /// </summary>
        private async void ConnectAsync()
        {
            LogInformation("正在连接服务器...");

            CanClickConnectionButton = false;
            CanEditDeviceId = false;

            var saveInfo = _saveInfoService.Read<MainWindowSaveInfo>();
            var hasAny = false;

            if (saveInfo.DeviceId != this.DeviceId)
            {
                saveInfo.DeviceId = this.DeviceId;
                hasAny = true;
            }

            if (saveInfo.Port != this.Port)
            {
                saveInfo.Port = this.Port;
                hasAny = true;
            }

            if (saveInfo.IPAddress != this.IPAddress)
            {
                saveInfo.IPAddress = this.IPAddress;
                hasAny = true;
            }

            if (hasAny)
            {
                // 更新存储
                _saveInfoService.Write(saveInfo);
            }

            if (string.IsNullOrEmpty(this.DeviceId))
            {
                LogError("请输入设备资源号！");
            }

            if (string.IsNullOrEmpty(this.IPAddress))
            {
                LogError("请输入IP地址！");
            }

            if (!string.IsNullOrEmpty(this.IPAddress)
                && !string.IsNullOrEmpty(this.DeviceId))
            {
                if (await _smart200Service.TestConnectAsync(this.IPAddress, this.Port))
                {
                    LogSuccess("PLC 设备可用");
                }
                else
                {
                    LogError($"{this.IPAddress}:{this.Port} 设备测试连接失败");
                }
            }

            var service = new SignalRClientService(this.DeviceId, this._appLog);

            service.ConnectionCallback -= ServiceConnectionCallback; ;
            service.ConnectionCallback += ServiceConnectionCallback; ;

            await service.ConnectAsync();

            HubConnected = service.IsConnected;

            if (!service.IsConnected)
            {
                // 开启交互
                CanClickConnectionButton = true;
                CanEditDeviceId = true;
            }
            else
            {
                // 保存实例
                _signalRClientService = service;
                _signalRClientService.ClassifyMeterial -= OnClassifyMeterial;
                _signalRClientService.ClassifyMeterial += OnClassifyMeterial;

                LogSuccess("服务器已连接");

                ConnectionButtonContent = "断开连接";
                CanClickConnectionButton = true;
                CanEditDeviceId = false;
            }
        }

        private void OnClassifyMeterial(object? sender, FlyingEye.ApplicationContracts.ClassifyMeterialMessage e)
        {
            Application.Current.Dispatcher.InvokeAsync(new Action(() =>
            {
                UpdateTopTip(e.Message);
            }));
        }

        /// <summary>
        /// 断开所有连接
        /// </summary>
        private async void DisconnectAsync()
        {
            // 失能按钮
            CanClickConnectionButton = false;
            LogInformation("正在断开服务器连接...");

            // 如果已经连接服务器，则断开连接
            if (_signalRClientService != null)
            {
                await _signalRClientService.DisconnectAsync();

                // 重新设置状态
                ConnectionButtonContent = "连接服务器";

                // 设置 Hub 状态为未连接
                HubConnected = false;

                // 释放资源
                _signalRClientService = null;
            }

            // 断开连接之后，要可以编辑
            CanEditDeviceId = true;
            // 断开连接之后，要可以点击连接
            CanClickConnectionButton = true;

            LogInformation("服务器已断开！");
        }

        private void ServiceConnectionCallback(object? sender, FlyingEye.ApplicationContracts.SignalRHubs.ConnectionCallbackEventArgs e)
        {
            LogInformation(e.Message);
        }

        private void OnTimesUp(object? sender, EventArgs e)
        {
            TimerVisibility = Visibility.Collapsed;
            ControlEnable = false;
        }

        private int _tickValue;

        public int TickValue
        {
            get { return _tickValue; }
            set
            {
                SetProperty(ref _tickValue, value);
            }
        }

        private Visibility _timerVisibility;

        public Visibility TimerVisibility
        {
            get { return _timerVisibility; }
            set
            {
                SetProperty(ref _timerVisibility, value);
            }
        }

        private void OnTick(object? sender, TimeSpan e)
        {
            TickValue = (int)Math.Round(e.TotalSeconds, MidpointRounding.AwayFromZero); ;
        }

        private string? _sfc;

        public string? Sfc
        {
            get { return _sfc; }
            set
            {
                SetProperty(ref _sfc, value);
            }
        }

        public ICommand UserManageCommand { get; set; }

        private void OnUserManage()
        {
            var service = _services.GetRequiredService<IAuthenticationService>();

            if (service.AdminAuthenticate())
            {
                var window = _services.GetRequiredService<UserManagerWindow>();
                window.DataContext = _services.GetRequiredService<UserManagerWindowViewModel>();
                window.ShowDialog();
            }
            else
            {
                LogInformation("需要管理员权限才可执行此操作!");
            }
        }

        public ICommand ConfigCommand { get; set; }

        private void OnConfig()
        {
            var service = _services.GetRequiredService<IAuthenticationService>();

            if (service.AdminAuthenticate() || service.PEAuthenticate() || service.MEAuthenticate())
            {
                var window = _services.GetRequiredService<MesConfigurationWindow>();
                window.DataContext = _services.GetRequiredService<MesConfigurationWindowViewModel>();
                window.ShowDialog();
            }
            else
            {
                LogInformation("需要PE或ME权限才可执行此操作!");
            }
        }

        private LogInfo? _logInfo;

        public LogInfo? LogInfo
        {
            get { return _logInfo; }
            set
            {
                SetProperty(ref _logInfo, value);
            }
        }

        private void LogError(string message)
        {
            _operationLog.Info(message);

            Application.Current.Dispatcher.Invoke(new Action(() =>
            {
                LogInfo = new LogInfo(Brushes.Red, LogFormator.DateTimeFormatting(message));
            }));
        }

        private void LogInformation(string message)
        {
            _operationLog.Info(message);

            Application.Current.Dispatcher.Invoke(new Action(() =>
            {
                LogInfo = new LogInfo(Brushes.Black, LogFormator.DateTimeFormatting(message));
            }));
        }

        private void LogSuccess(string message)
        {
            _operationLog.Info(message);

            Application.Current.Dispatcher.Invoke(new Action(() =>
            {
                LogInfo = new LogInfo(Brushes.Green, LogFormator.DateTimeFormatting(message));
            }));
        }

        public ICommand AuthenticateCommand { get; set; }

        public ICommand UnregisterCommand { get; set; }

        private async void OnUnregister()
        {
            var service = _services.GetRequiredService<IAuthenticationService>();

            if (service.HasAuthentication)
            {
                await service.UnauthenticateAsync();
                LogSuccess("权限已注销！");
                _timer.Stop();
            }
            else
            {
                LogInformation("您还未进行权限认证！");
            }
        }

        private async void OnAuthenticate(object arg)
        {
            var passwordBox = (PasswordBox)arg;
            var password = passwordBox.Password;

            if (string.IsNullOrWhiteSpace(password))
            {
                LogError("请输入密码！");
                return;
            }

            if (password.Length < 6)
            {
                LogError("密码长度必须大于6！");
                return;
            }

            var authen = _services.GetRequiredService<IAuthenticationService>();

            try
            {
                var result = await authen.AuthenticateAsync(password);
                passwordBox.Password = string.Empty;

                if (result)
                {
                    ControlEnable = true;
                    LogSuccess("权限认证成功！");
                    _timer.Start(TimeSpan.FromMinutes(3));
                    TimerVisibility = Visibility.Visible;
                    ControlEnable = true;
                }
                else
                {
                    LogError("权限认证失败！");
                    _timer.Stop();
                }
            }
            catch (Exception)
            {
                LogError("权限认证出现错误！");
                _timer.Stop();
            }
        }

        private bool _controlEnable;

        public bool ControlEnable
        {
            get { return _controlEnable; }
            set
            {
                SetProperty(ref _controlEnable, value);
            }
        }

        private int _positionSelectedIndex;

        public int PositionSelectedIndex
        {
            get { return _positionSelectedIndex; }
            set
            {
                ChangeTipWindowPosition(value);
                SetProperty(ref _positionSelectedIndex, value);
            }
        }

        private void ChangeTipWindowPosition(int selected)
        {
            var viweModel = _services.GetRequiredService<TopTipWindowViewModel>();

            switch (selected)
            {
                case 0:
                    viweModel.ShowLeft();
                    break;

                case 1:
                    viweModel.ShowRight();
                    break;

                default:
                    viweModel.Hide();
                    break;
            };
        }

        /// <summary>
        /// 提示窗口坐标列表。
        /// </summary>
        public List<string> PositionList { get; set; }

        public ICommand StartCommand { get; set; }

        private bool startButtonScanf = false;

        private async void OnInbound()
        {
            if (startButtonScanf)
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(this.Sfc))
            {
                LogError("SFC数据不能为空。");
                return;
            }

            startButtonScanf = true;
            var mesService = _services.GetRequiredService<IInBoundMesService>();
            var mesConfig = await _saveInfoService.ReadAsync<MesConfigurationSaveInfo>();
            var requestMessage = _mapper.Map<StartRequestMessageDto>(mesConfig);
            requestMessage.Sfc = this.Sfc;

            StartResponseMessageDto result;
            try
            {
                result = await mesService.PostAsync(requestMessage);
            }
            catch (Exception)
            {
                LogError($"SFC {this.Sfc} 分类失败，请检查 MES 配置！");
                startButtonScanf = false;
                return;
            }

            if (result.Success)
            {
                LogSuccess($"SFC {this.Sfc} 分类成功！");
                UpdateTopTip(result.Message);
            }
            else
            {
                LogError($"SFC {this.Sfc} 分类失败！");
                LogError(result.Message ?? string.Empty);
                UpdateDefaultTopTip();
            }

            startButtonScanf = false;
        }

        private void UpdateDefaultTopTip()
        {
            var viewModel = _services.GetRequiredService<TopTipWindowViewModel>();
            viewModel.WindowBrush = Brushes.Gray;
            viewModel.Content = "未进行分类";
        }

        public async void UpdateTopTip(string? message)
        {
            // 保存当前级片信息
            _currentMessage = message;

            var viewModel = _services.GetRequiredService<TopTipWindowViewModel>();

            if (string.IsNullOrWhiteSpace(message) || !message.Any(charItem => charItem > '0' && charItem < '9'))
            {
                LogError($"MES不支持极片分类");
                viewModel.WindowBrush = Brushes.Gray;
                viewModel.Content = "MES不支持极片分类";
            }
            else
            {
                var charValue = message.FirstOrDefault(charItem => charItem > '0' && charItem < '9');
                (Brush brush, string message) value;
                switch (charValue)
                {
                    case '1':
                        value = (Brushes.Red, "红色类别极片");
                        await _smart200Service.WriteRedSignalAsync(this.IPAddress, this.Port);
                        break;
                    case '2':
                        value = (Brushes.Yellow, "黄色类别极片");
                        await _smart200Service.WriteYellowSignalAsync(this.IPAddress, this.Port);
                        break;
                    case '3':
                        value = (Brushes.White, "白色类别极片");
                        await _smart200Service.WriteWhiteSignalAsync(this.IPAddress, this.Port);
                        break;
                    default:
                        value = (Brushes.Gray, $"不能识别极片类型{charValue}");
                        break;
                }

                viewModel.WindowBrush = value.brush;

                if (string.IsNullOrWhiteSpace(Sfc))
                {
                    _operationLog.Info(value.message);
                    viewModel.Content = value.message;
                }
                else
                {
                    viewModel.Content = Sfc;
                }
            }
        }

        private void OnInbound(object? sender, InBoundEventArgs e)
        {
            // 使用 Dispatcher 切换到 UI 线程更新 UI
            Application.Current.Dispatcher.Invoke(() =>
            {
                this.Sfc = e.Sfc;

                if (e.Succeess)
                {
                    LogSuccess($"SFC {this.Sfc} 分类成功！");
                    UpdateTopTip(e.Message);
                }
                else
                {
                    LogError($"SFC {this.Sfc} 分类失败！");
                    LogError(e.Message ?? string.Empty);
                    UpdateDefaultTopTip();
                }
            });
        }
    }
}
